<?php

namespace App\Models\Ddaman;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Validator;
use Tymon\JWTAuth\Contracts\JWTSubject;

use App\Common\model\DmError;

use Illuminate\Support\Facades\Redis;


class Admin extends Authenticatable implements JWTSubject
{
    use HasFactory, Notifiable , DmError;

    protected $table="sy_user";

    //const CREATED_AT = null;
    //const UPDATED_AT = null;


    protected $fillable = [
        'guid','name','salt', 'password','ipaddr','branch_id'
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
        'salt',
    ];

    protected $auth = "admin";

    public $rule = [
        'name' => 'required|string|between:2,100|unique:sy_user',
        'password' => 'required|string|confirmed|min:6',
    ];

    public $editRule = [
        'id' => 'required',
        'name' => 'required|string|between:2,100',
    ];

    public $message = [
        'id.required' => '标识必须',
        'name.required' => '名称必须填写',
        'name.unique' => '名称不能重复',
        'password.required' => '密码必须填写',
        'password.confirmed' => '两次密码必须一致',
        'password.min' => '密码最小6位数字和字母组合',
    ];

    /*
     * 获取列表
     * */
    public function getList( $param = [] )
    {
        $limit = isset($param['limit']) ? $param['limit'] : 2;
        $where = [];

        if (isset($param['keywords']) && $param['keywords']){
            $keywords = trim($param['keywords']);
            $where[] = ['name','like',"%$keywords%"];
        }

        $field = array_merge(['id'],$this->fillable);
        $list = $this->where($where)->paginate($limit);
        $list->transForm(function ($item){
            $item->role_id = AdminRole::where('user_id',$item->id)->value('role_id');
            return $item;
        });
        return $list;
    }

    /*
     * 保存数据
     * */
    public function changes( $data , $rule)
    {
        $validator = Validator::make( $data ,$rule ,$this->message);
        if($validator->fails()){
            $this->error = $validator->errors()->toMsg();
            return false;
        }

        DB::beginTransaction();
        try {
            //dump($data);die;
            $data['branch_id'] = isset($data['branch_info']) && is_array($data['branch_info']) ? end($data['branch_info']) : NULL;
            $userData = stayFill($this->fillable,$data);
            $userData['ipaddr'] = get_client_ip();
            if (isset($data['id']) && $data['id'])
            {
                if (isset($userData['password']) && $userData['password']){
                    $userData['salt'] = rand_string(6);
                    $userData['password'] = bcrypt($data['password']);
                }
                $result = $this->where('id',$data['id'])->update($userData);
                if (!$result){
                    throw new \Exception('编辑失败 10001');
                }
                $data['user_id'] = $data['id'];
            }else{
                $userData = array_merge($userData,
                    ['guid' => getGuid()],
                    ['salt' => rand_string(6)],
                    ['password' => bcrypt($data['password'])]
                );
                $result = $this->create($userData);
                if (!$result){
                    throw new \Exception('新增失败 10001');
                }
                $data['user_id'] = $result->id;
            }


            //添加角色
            if (isset($data['role_id']) && $data['role_id'])
            {
                $where = [
                    ['user_id',$data['user_id']],
                ];
                $role = AdminRole::where($where)->first();
                //dump($role);die;
                if ($role){
                    $role->role_id = $data['role_id'];
                    $result = $role->save();
                }else{
                    $result = AdminRole::create([
                        'user_id'=>$data['user_id'],
                        'role_id'=>isset($data['role_id']) ? $data['role_id'] : 0
                    ]);
                }
                if (!$result){
                    throw new \Exception('保存失败 1002');
                }
            }


            DB::commit();
            return $result;
        }catch (\Exception $exception){
            DB::rollBack();
            $this->error = $exception->getMessage();
            return false;
        }
    }

    /*
     * 注册
     * */
    public  function register( $data )
    {
        $validator = Validator::make($data, [
            'name' => 'required|string|between:2,100|unique:sy_user',
            'password' => 'required|string|confirmed|min:6',
        ],$this->message);

        if($validator->fails()){
            $this->error = $validator->errors()->toMsg();
            return false;
        }
        DB::beginTransaction();
        try {
            //dump($data);die;
            $branchId = isset($data['branch_info']) && is_array($data['branch_info']) ? end($data['branch_info']) : NULL;
            $user = Admin::create(array_merge(
                $validator->validated(),
                ['guid' => getGuid()],
                ['salt' => rand_string(6)],
                ['branch_id' => $branchId],
                ['ipaddr' => get_client_ip()],
                ['password' => bcrypt($data['password'])]
            ));
            if (!$user){
                throw new \Exception('新增失败');
            }

            $info = self::getInfo($user['id']);

            //添加角色
            $result = AdminRole::create([
                'user_id'=>$user->id,
                'role_id'=>isset($data['role_id']) ? $data['role_id'] : 0
            ]);
            if (!$result){
                throw new \Exception('新增失败');
            }

            DB::commit();

            return  $info;
        }catch (\Exception $exception){
            DB::rollBack();
            $this->error = $exception->getMessage();
            return false;
        }
    }

    /*
     * 删除数据 软删除
     * */
    public function delSoft( $id )
    {
        $result = $this->where('id',$id)->delete();
        if (!$result){
            $this->error = "删除失败";
            return false;
        }
        return true;
    }


    /*
     * 登陆
     * */
    public function login( $data )
    {
        try {
            $validator = Validator::make($data, [
                'name' => 'required',
                'password' => 'required|string|min:6',
            ]);
            if ($validator->fails()) {
                throw new \Exception($validator->errors()->toMsg());
            }

            //账号或者密码错误 都会报错
            if (!$token = auth($this->auth)->attempt($validator->validated())) {
                throw new \Exception("用户未授权 或者用户名密码错误");
            }

            //登陆成功记录
            $this->loginLog($data,1);
            //dump($data);die;

            //登陆成功 token 记录
            $result = $this->authLogin( $data );

            return $result;

        }catch (\Exception $exception){

            $this->error = $exception->getMessage();
            //登陆失败记录
            $this->loginLog($data,0);

            return false;
        }


    }

    /*
     * 登陆成功 颁发 token 令牌
     * @param type 1 成功  0 失败
     * */
    protected function authLogin( $param )
    {
        $data = [];
        $data['ipaddr'] = get_client_ip();
        $data['token'] = $tgToken = md5(getGuid());
        $user = DB::table('sy_user')
            ->where('name',$param['name'])
            ->select('id','name')
            ->first();
        if ($user){
            $data['user_id'] = $user->id;
        }
        //过期时间
        $data['expires'] = date("Y-m-d H:i:s",strtotime('+15 hour',time()));
        $result = DB::table('sy_user_token')
            ->insert($data);

        //加入缓存 过期时间多少秒
        $outTime = strtotime($data['expires']) - time();
        $sign = "admin_token:".$data['token'];
        //测试 token
        $outTime2 = strtotime('2022-12-31 00:00:00') - time();
        Redis::setex($sign,$outTime2,$data['token']);

        return $this->createNewToken( $data['token'] );
    }


    /*
     * 登陆记录
     * @param type 1 成功  0 失败
     * */
    protected function loginLog( $param , $type = 0)
    {
        $name = $param['name'];
        $data = [];
        $user = DB::table('sy_user')
            ->where('name',$name)
            ->select('id','name')
            ->first();
        if ($user){
            $data['user_id'] = $user->id;
        }

        if ((int)$type === 0){
            $data['content'] = "【 $name 】 - " .  $this->error;
        }else{
            $data['content'] = "【 $name 】 - 登陆成功..." ;
        }
        $data['logged'] = $type;
        $data['ipaddr'] = get_client_ip();
        //$data['creation_time'] = date("Y-m-d H:i:s");
        $result = AdminLogin::create($data);
        return $result;
    }


    /**
     * Get the token array structure.
     *
     * @param  string $token
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function createNewToken( $token )
    {
        $data = [
            'access_token' => $token,
            'token_type' => 'bearer',
            'expires_in' => auth($this->auth)->factory()->getTTL() * 60,
            'user' => auth($this->auth)->user()
        ];

        return $data;
    }

    /*
     * 获取用户信息
     * */
    public static function getInfo( $uid )
    {
        $info = DB::table("sy_user")
            ->where([
                'id'=>$uid
            ])
            ->select('name','id as uid')
            ->first();
        return $info;
    }


    /**
     * Get the identifier that will be stored in the subject claim of the JWT.
     *
     * @return mixed
     */
    public function getJWTIdentifier() {
        return $this->getKey();
    }
    /**
     * Return a key value array, containing any custom claims to be added to the JWT.
     *
     * @return array
     */
    public function getJWTCustomClaims() {
        return [];
    }





}
